home *** CD-ROM | disk | FTP | other *** search
/ Linux Cubed Series 2: Applications / Linux Cubed Series 2 - Applications.iso / hamradio / tnos-2.000 / tnos-2 / timer.c < prev    next >
C/C++ Source or Header  |  1996-07-21  |  7KB  |  307 lines

  1. /* General purpose software timer facilities
  2.  * Copyright 1991 Phil Karn, KA9Q
  3.  */
  4. #include "global.h"
  5. #include "commands.h"
  6. #include "timer.h"
  7. #include "proc.h"
  8. #include "daemon.h"
  9. #include "hardware.h"
  10. #include "socket.h"
  11. #ifdef BSD
  12. #include <errno.h>
  13. #endif
  14.  
  15. #if !defined(_lint) && !defined(MSDOS)
  16. static char rcsid[] OPTIONAL = "$Id: timer.c,v 1.12 1996/07/21 23:54:49 root Exp root $";
  17. #endif
  18.  
  19. /* Head of running timer chain.
  20.  * The list of running timers is sorted in increasing order of expiration;
  21.  * i.e., the first timer to expire is always at the head of the list.
  22.  */
  23. struct timer *Timers;
  24.  
  25. static void t_alarm __ARGS ((void *x));
  26.  
  27.  
  28. /* Process that handles clock ticks */
  29. /* Fixed to solve some timing problems when multiple ticks
  30.  * get handled at once... from Walt Corey, KZ1F
  31.  */
  32. void
  33. timerproc (i, v1, v2)
  34. int i OPTIONAL;
  35. void *v1 OPTIONAL, *v2 OPTIONAL;
  36. {
  37. register struct timer *t, *p;
  38. register struct timer *expired;
  39. char i_state;
  40. int tmp;
  41. #ifndef UNIX
  42. void (**vf) (void);
  43. #endif
  44.  
  45.     for ( ; ; ) {
  46.         /* Atomic read and decrement of Tick */
  47.         for ( ; ; ) {
  48.             i_state = (char) dirps ();
  49.             tmp = Tick;
  50.             if (tmp != 0) {
  51.                 Tick--;
  52.                 restore (i_state);
  53.                 break;
  54.             }
  55.             restore (i_state);
  56.             pwait (&Tick);
  57.         }
  58. #ifndef TNOS_68K
  59.         if (!istate ()) {
  60.             restore (1);
  61.             printf ("timer: ints were off!\n");
  62.             (void) fflush (stdout);    /*lint !e740 * make sure it gets out */
  63.         }
  64. #endif
  65.  
  66. #ifndef UNIX
  67.         /* Call the functions listed in config.c */
  68.         for (vf = Cfunc; *vf != NULL; vf++)
  69.             (*vf) ();
  70. #endif
  71.  
  72.         tflush ();    /* Flush current session output */
  73.         pwait (NULL);    /* Let them all do their writes */
  74. #ifndef UNIX
  75.         rflush ();    /* Flush out buffered console stuff */
  76.         fflush (stdout);/* And flush out stdout too */
  77. #endif
  78.  
  79.         if (Timers == NULLTIMER)
  80.             continue;    /* No active timers, all done */
  81.  
  82.         /* Initialize null expired timer list */
  83.         expired = NULLTIMER;
  84.  
  85.         /* Move expired timers to expired list. Note use of
  86.          * subtraction and comparison to zero rather than the
  87.          * more obvious simple comparison; this avoids
  88.          * problems when the clock count wraps around.
  89.          */
  90.         while (Timers != NULLTIMER && (Clock - Timers->expiration) >= 0) {
  91.             if (Timers->next == Timers) {
  92.                 printf ("PANIC: Timer loop at %lx\n",
  93.                     (long) Timers);
  94.                 iostop ();
  95.                 exit (1);
  96.             }
  97.             /* Save Timers since stop_timer will change it */
  98.             t = Timers;
  99.             stop_timer (t);
  100.             /* Add to expired timer list */
  101.             if (expired == NULLTIMER) {
  102.                 expired = t;
  103.             } else {
  104.                 for (p = expired; p->next != NULLTIMER; p = p->next) ;
  105.                 p->next = t;    /* place at end of chain */
  106.             }
  107.             t->next = NULLTIMER;
  108.         }
  109.         /* Now go through the list of expired timers, removing each
  110.          * one and kicking the notify function, if there is one
  111.          * Note that the state should ne TIMER_STOP. We just stopped
  112.          * it remember? Now is someone else changed it, ignore timer.
  113.          */
  114.         while ((t = expired) != NULLTIMER) {
  115.             expired = t->next;
  116.             if (t->state == TIMER_STOP) {
  117.                 t->state = TIMER_EXPIRE;
  118.                 if (t->func)
  119.                     (*t->func) (t->arg);
  120.             }
  121.         }
  122.         pwait (NULL);    /* Let them run before handling more ticks */
  123.     }
  124. }
  125.  
  126.  
  127. /* Start a timer */
  128. void
  129. start_timer (t)
  130. struct timer *t;
  131. {
  132. register struct timer *tnext;
  133. struct timer *tprev = NULLTIMER;
  134.  
  135.     if (t == NULLTIMER)
  136.         return;
  137.     if (t->state == TIMER_RUN)
  138.         stop_timer (t);
  139.     if (t->duration == 0)
  140.         return;        /* A duration value of 0 disables the timer */
  141.  
  142.     t->next = NULLTIMER;    /* insure forward chain is NULL */
  143.     t->expiration = Clock + t->duration;
  144.     t->state = TIMER_RUN;
  145.  
  146.     /* Find right place on list for this guy. Once again, note use
  147.      * of subtraction and comparison with zero rather than direct
  148.      * comparison of expiration times.
  149.      */
  150.     for (tnext = Timers; tnext != NULLTIMER; tprev = tnext, tnext = tnext->next) {
  151.         if ((tnext->expiration - t->expiration) >= 0)
  152.             break;
  153.     }
  154.     /* At this point, tprev points to the entry that should go right
  155.      * before us, and tnext points to the entry just after us. Either or
  156.      * both may be null.
  157.      */
  158.     if (tprev == NULLTIMER)
  159.         Timers = t;    /* Put at beginning */
  160.     else
  161.         tprev->next = t;
  162.  
  163.     t->next = tnext;
  164. }
  165.  
  166.  
  167. /* Stop a timer */
  168. void
  169. stop_timer (timer)
  170. struct timer *timer;
  171. {
  172. register struct timer *t;
  173. struct timer *tlast = NULLTIMER;
  174.  
  175.     if (timer == NULLTIMER || timer->state != TIMER_RUN)
  176.         return;
  177.  
  178.     /* Verify that timer is really on list */
  179.     for (t = Timers; t != NULLTIMER; tlast = t, t = t->next)
  180.         if (t == timer)
  181.             break;
  182.  
  183.     if (t == NULLTIMER)
  184.         return;        /* Should probably panic here */
  185.  
  186.     /* Delete from active timer list */
  187.     if (tlast != NULLTIMER)
  188.         tlast->next = t->next;
  189.     else
  190.         Timers = t->next;    /* Was first on list */
  191.  
  192.     t->state = TIMER_STOP;
  193. }
  194.  
  195.  
  196. /* Return milliseconds remaining on this timer */
  197. int32
  198. read_timer (t)
  199. struct timer *t;
  200. {
  201. int32 remaining;
  202.  
  203.     if (t == NULLTIMER || t->state != TIMER_RUN)
  204.         return 0;
  205.     remaining = t->expiration - Clock;
  206.     if (remaining <= 0)
  207.         return 0;    /* Already expired */
  208.     else
  209.         return remaining * MSPTICK;
  210. }
  211.  
  212.  
  213. void
  214. set_timer (t, interval)
  215. struct timer *t;
  216. int32 interval;
  217. {
  218. #ifndef TNOS_68K
  219. #define FUDGE 1
  220. #else
  221. #define FUDGE 0
  222. #endif
  223.  
  224.     if (t == NULLTIMER)
  225.         return;
  226.     /* Round the interval up to the next full tick, and then
  227.      * add another tick to guarantee that the timeout will not
  228.      * occur before the interval is up. This is necessary because
  229.      * we're asynchonous with the system clock.
  230.      */
  231.     if (interval != 0)
  232.         t->duration = FUDGE + (interval + MSPTICK - 1) / MSPTICK;
  233.     else
  234.         t->duration = 0;
  235. }
  236.  
  237.  
  238. /* Delay process for specified number of milliseconds.
  239.  * Normally returns 0; returns -1 if aborted by alarm.
  240.  */
  241. int
  242. mspause (ms)
  243. int32 ms;
  244. {
  245. int val;
  246.  
  247.     if (Curproc == NULLPROC || ms == 0)
  248.         return 0;
  249.     alarm (ms);
  250.     /* The actual event doesn't matter, since we'll be alerted */
  251.     val = 0;
  252.     while (Curproc->alarm.state == TIMER_RUN) {
  253.         if ((val = pwait (Curproc)) != 0)
  254.             break;
  255.     }
  256.     alarm (0L);        /* Make sure it's stopped, in case we were killed */
  257.     return (val == EALARM) ? 0 : -1;
  258. }
  259.  
  260.  
  261. static void
  262. t_alarm (x)
  263. void *x;
  264. {
  265.     alert ((struct proc *) x, EALARM);
  266. }
  267.  
  268.  
  269. /* Send signal to current process after specified number of milliseconds */
  270. void
  271. alarm (ms)
  272. int32 ms;
  273. {
  274.     if (Curproc != NULLPROC) {
  275.         set_timer (&Curproc->alarm, ms);
  276.         Curproc->alarm.func = t_alarm;
  277.         Curproc->alarm.arg = (char *) Curproc;
  278.         start_timer (&Curproc->alarm);
  279.     }
  280. }
  281.  
  282.  
  283. /* Convert time count in seconds to printable days:hr:min:sec format */
  284. char *
  285. tformat (t)
  286. int32 t;
  287. {
  288. static char buf[17];
  289. int days, hrs, mins, secs;
  290. int minus = 0;
  291.  
  292.     if (t < 0) {
  293.         t = -t;
  294.         minus = 1;
  295.     }
  296.  
  297.     secs = t % 60;
  298.     t /= 60;
  299.     mins = t % 60;
  300.     t /= 60;
  301.     hrs = t % 24;
  302.     days = t / 24;
  303.  
  304.     sprintf (buf, "%s%d:%02d:%02d:%02d", (minus) ? "-" : "", days, hrs, mins, secs);
  305.     return buf;
  306. }
  307.